﻿using System;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Geometries;

namespace YJKGridTopologyCal.Index.Chain
{
	public class MonotoneChain
	{
		public MonotoneChain(Coordinate[] pts, int start, int end, object context)
		{
			this._pts = pts;
			this._start = start;
			this._end = end;
			this._context = context;
		}

		public int Id { get; set; }

		public object Context
		{
			get
			{
				return this._context;
			}
		}

		public Envelope Envelope
		{
			get
			{
				if (this._env == null)
				{
					Coordinate p = this._pts[this._start];
					Coordinate p2 = this._pts[this._end];
					this._env = new Envelope(p, p2);
				}
				return this._env;
			}
		}

		public int StartIndex
		{
			get
			{
				return this._start;
			}
		}

		public int EndIndex
		{
			get
			{
				return this._end;
			}
		}

		public void GetLineSegment(int index, ref LineSegment ls)
		{
			ls.P0 = this._pts[index];
			ls.P1 = this._pts[index + 1];
		}

		public Coordinate[] Coordinates
		{
			get
			{
				Coordinate[] array = new Coordinate[this._end - this._start + 1];
				int num = 0;
				for (int i = this._start; i <= this._end; i++)
				{
					array[num++] = this._pts[i];
				}
				return array;
			}
		}

		public void Select(Envelope searchEnv, MonotoneChainSelectAction mcs)
		{
			this.ComputeSelect(searchEnv, this._start, this._end, mcs);
		}

		private void ComputeSelect(Envelope searchEnv, int start0, int end0, MonotoneChainSelectAction mcs)
		{
			Coordinate p = this._pts[start0];
			Coordinate p2 = this._pts[end0];
			mcs.TempEnv1.Init(p, p2);
			if (end0 - start0 == 1)
			{
				mcs.Select(this, start0);
				return;
			}
			if (!searchEnv.Intersects(mcs.TempEnv1))
			{
				return;
			}
			int num = (start0 + end0) / 2;
			if (start0 < num)
			{
				this.ComputeSelect(searchEnv, start0, num, mcs);
			}
			if (num < end0)
			{
				this.ComputeSelect(searchEnv, num, end0, mcs);
			}
		}

		public void ComputeOverlaps(MonotoneChain mc, MonotoneChainOverlapAction mco)
		{
			this.ComputeOverlaps(this._start, this._end, mc, mc._start, mc._end, mco);
		}

		private void ComputeOverlaps(int start0, int end0, MonotoneChain mc, int start1, int end1, MonotoneChainOverlapAction mco)
		{
			Coordinate p = this._pts[start0];
			Coordinate p2 = this._pts[end0];
			Coordinate p3 = mc._pts[start1];
			Coordinate p4 = mc._pts[end1];
			if (end0 - start0 == 1 && end1 - start1 == 1)
			{
				mco.Overlap(this, start0, mc, start1);
				return;
			}
			mco.TempEnv1.Init(p, p2);
			mco.TempEnv2.Init(p3, p4);
			if (!mco.TempEnv1.Intersects(mco.TempEnv2))
			{
				return;
			}
			int num = (start0 + end0) / 2;
			int num2 = (start1 + end1) / 2;
			if (start0 < num)
			{
				if (start1 < num2)
				{
					this.ComputeOverlaps(start0, num, mc, start1, num2, mco);
				}
				if (num2 < end1)
				{
					this.ComputeOverlaps(start0, num, mc, num2, end1, mco);
				}
			}
			if (num < end0)
			{
				if (start1 < num2)
				{
					this.ComputeOverlaps(num, end0, mc, start1, num2, mco);
				}
				if (num2 < end1)
				{
					this.ComputeOverlaps(num, end0, mc, num2, end1, mco);
				}
			}
		}

		private readonly Coordinate[] _pts;

		private readonly int _start;

		private readonly int _end;

		private Envelope _env;

		private readonly object _context;
	}
}
